<?php
/**
 * @package es2reveng
 * @name ES2 .DFN font unpacker
 * @author marco 'harddisk' schuster
 * @license GPL v3
 */

require 'helpers.php';
$f = $argv[1];
echo "viewing file $f\n";
if (!is_file($f))
	die("file broken");

$fp = fopen($f, "rb");

//check magic bytes
$offset = -1; //the ++ incrementor will read at byte 1 if this is omitted
$magic = getchar($fp, ++$offset);
$magic .= getchar($fp, ++$offset);
$magic .= getchar($fp, ++$offset);
$magic .= getchar($fp, ++$offset);
if ($magic != "\x05\x00\x28\x00")
	die("wrong magic code. this is not a valid DFN file!\n");

//get the file size (after the 8 bytes header)
$b1 = getchar($fp, ++$offset, false);
$b2 = getchar($fp, ++$offset, false);
$b3 = getchar($fp, ++$offset, false);
$b4 = getchar($fp, ++$offset, false);
$filesize = le_to_int($b1, $b2, $b3, $b4);

//get the element count
$b1 = getchar($fp, ++$offset, false);
$b2 = getchar($fp, ++$offset, false);
$b3 = getchar($fp, ++$offset, false);
$b4 = getchar($fp, ++$offset, false);
$el_count = le_to_int($b1, $b2, $b3, $b4);

//get unk1
$b1 = getchar($fp, ++$offset);
$b2 = getchar($fp, ++$offset);
$unk1 = $b1.$b2;//le_to_int($b1, $b2);

//get block length 1
$b1 = getchar($fp, ++$offset,false);
$b2 = getchar($fp, ++$offset,false);
$bl1 = le_to_int($b1, $b2);

//get unk3
$b1 = getchar($fp, ++$offset);
$b2 = getchar($fp, ++$offset);
$unk3 = $b1.$b2;//le_to_int($b1, $b2);

//get block length 2 (must be equal to block length 1) 
$b1 = getchar($fp, ++$offset,false);
$b2 = getchar($fp, ++$offset,false);
$bl2 = le_to_int($b1, $b2);
if($bl1!=$bl2)
	echo "warning: block lengths differ (spec 1: $bl1, spec 2: $bl2)!\n";

//get unk5
$b1 = getchar($fp, ++$offset);
$b2 = getchar($fp, ++$offset);
$unk5 = $b1.$b2;//le_to_int($b1, $b2);

//get unk6
$b1 = getchar($fp, ++$offset);
$b2 = getchar($fp, ++$offset);
$b3 = getchar($fp, ++$offset);
$b4 = getchar($fp, ++$offset);
$unk6 = $b1.$b2.$b3.$b4;//le_to_int($b1, $b2, $b3, $b4);

//get unk7
$b1 = getchar($fp, ++$offset);
$b2 = getchar($fp, ++$offset);
$b3 = getchar($fp, ++$offset);
$b4 = getchar($fp, ++$offset);
$unk7 = $b1.$b2.$b3.$b4;//le_to_int($b1, $b2, $b3, $b4);

//get the primary payload size
$b1 = getchar($fp, ++$offset, false);
$b2 = getchar($fp, ++$offset, false);
$b3 = getchar($fp, ++$offset, false);
$b4 = getchar($fp, ++$offset, false);
$payload_len = le_to_int($b1, $b2, $b3, $b4);

echo "font file, length $filesize bytes (".($filesize+8)." inc. hdr), $el_count elements, primary payload size $payload_len, block size $bl1\n";
echo "unknown blocks:\n\t1: '".strtohex($unk1)."'\n\t3: '".strtohex($unk3)."'\n\t5: '".strtohex($unk5)."'\n\t6: '".strtohex($unk6)."'\n\t7: '".strtohex($unk7)."'\n";

//we first read the length and offset info...
$payload_start=$offset;
$offset+=$payload_len;
echo "starting to read @ $offset\n";

//get the payload separation offset
$payloads=array();
for($i=0;$i<$el_count;$i++) {
	$b1 = getchar($fp, ++$offset, false);
	$b2 = getchar($fp, ++$offset, false);
	$b3 = getchar($fp, ++$offset, false);
	$b4 = getchar($fp, ++$offset, false);
	$payloads[$i]["offset"] = le_to_int($b1, $b2, $b3, $b4);
}
//add a fake "last" element so the length calculation works
$payloads[$i]["offset"]=$payload_len;

//get the length
for($i=0;$i<$el_count;$i++)
	$payloads[$i]["length"]=getchar($fp, ++$offset, false);

//get the payload data
$offset_backup=$offset;
$offset=$payload_start;
for($i=0;$i<$el_count;$i++) {
	$payloads[$i]["actual_length"]=$payloads[$i+1]["offset"]-$payloads[$i]["offset"];
	if($payloads[$i]["length"]*$bl1!=$payloads[$i]["actual_length"])
		echo "warning for element $i: length ".$payloads[$i]["actual_length"].
		" does not equal target length (".$payloads[$i]["length"]."*$bl1)\n";
	$payloads[$i]["data"]="";
	for($j=0;$j<$payloads[$i]["actual_length"];$j++) {
		$payloads[$i]["data"].=getchar($fp, ++$offset);
	}
	echo	"payload element $i: begin at base+".$payloads[$i]["offset"].
			", target length ".$payloads[$i]["length"].", actual len ".$payloads[$i]["actual_length"].
			", data:\n\t".strtohex($payloads[$i]["data"])."\n";	
}

$offset=$offset_backup; //avoid an error due to the jumping

if ($offset + 1 != filesize($f)) //take care: offset is null-based, file-size is not
	echo "arrived at structural end (offset is $offset, flen is ".filesize($f)."), but there are still some bytes left\n";
else
	echo "file parse OK\n";
?>